green <- miscgis::miscgis_pals$tableau_cat[["green"]]
blue <- miscgis::miscgis_pals$tableau_cat[["blue"]]
orange <- miscgis::miscgis_pals$tableau_cat[["orange"]]
red <- miscgis::miscgis_pals$tableau_cat[["red"]]
teal <- miscgis::miscgis_pals$tableau_cat[["teal"]]
pal_rgb_4 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue")] %>% unlist %>% palette()
pal_rgb_4 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue")] %>% unlist %>% palette()
pal_rgb_6 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue","orange","purple")] %>% unlist %>% palette()
pal_rgb_6 <- miscgis::miscgis_pals$tableau_cat[c("red","gold","green","blue","orange","purple")] %>% unlist %>% palette()

Below is a collection of spatial datasets used in this project.

King County Boundary

if(!file.exists(root_file('./1-data/4-interim/kc-noclip-sf.rds'))){
        tigris::counties(state = "53") %>% 
                st_transform(crs_proj@projargs) %>% 
                filter(NAME %in% 'King') %>% 
                write_rds(root_file('./1-data/4-interim/kc-noclip-sf.rds'))
}
kc_noclip_sf <- read_rds(root_file('./1-data/4-interim/kc-noclip-sf.rds'))
myLfltGrey(data = as(kc_noclip_sf,'Spatial')) %>% 
        myLfltOpts() %>% 
        addPolygons(color = red,opacity = 1,fillColor = red,fillOpacity = .5)

King County Subdivision Boundary

if(!file.exists(root_file('1-data/4-interim/seattle-ccd-noclip-sf.rds'))){
        tigris::county_subdivisions(state = "53",county = "033") %>% 
                st_transform(crs_proj@projargs) %>% 
                filter(NAME %in% "Seattle") %>% 
                mutate(NAME = 'Seattle CCD') %>% 
                write_rds(root_file('1-data/4-interim/seattle-ccd-noclip-sf.rds'))
}
sea_ccd_noclip_sf <- read_rds(root_file('1-data/4-interim/seattle-ccd-noclip-sf.rds'))
myLfltGrey(data = as(sea_ccd_noclip_sf,'Spatial')) %>% 
        myLfltOpts() %>% 
        addPolygons(color = blue,opacity = 1,fillColor = blue,fillOpacity = .5)

Seattle Boundary

if(!file.exists(root_file('1-data/4-interim/seattle-noclip-sf.rds'))){
        tigris::places(state = 53) %>%
                tigris::filter_place(place = "Seattle") %>%
                st_transform(crs_proj@projargs) %>% 
                write_rds(root_file('1-data/4-interim/seattle-noclip-sf.rds'))
        
}
sea_noclip_sf <- read_rds(root_file('1-data/4-interim/seattle-noclip-sf.rds'))
myLfltGrey(data = as(sea_noclip_sf,'Spatial')) %>% 
        myLfltOpts() %>% 
        addPolygons(color = green,opacity = 1,fillColor = green,fillOpacity = .5)

Tracts in King County

Although this assessment is primarily focused on three communities within the Seattle CCD subdivision of King County, one of the indicators (housing market conditions) uses neighboring tracts to determine displacement risk. Some of the neighboring tracts are part of other county subdivision, but rather than targeting just those specific tracts, this method collects data for all King County tracts and then runs the analysis on the appropriate subsets.

In the absence of a straight-forward method for identifying all the census tracts in the Seattle CCD subdivision of King County, it is possible to extract this information from American Factfinder. This tutorial describes how to use the American Factfinder interface to extract a list of all “all tracts within (or partially within) a census place”; substituting “county subdivision” for “place” will retrieve the desired results.

Tract boundaries sometimes change over time, particularly on years when the decennial census is conducted. While this project will primarily use the current set of boundaries, it is necessary to collect the tract boundaries of the 2000-2009 time period so that these datasets can be visually represented in choropleth diagrams.

# 2015 tract boundaries
if(!file.exists(root_file('1-data/4-interim/tr-kc-noclip-2015-sf.rds'))){
        
        # Seattle CCD tracts 
        # Note: because this selection includes all tracts "within or partially-within" the Seattle CC,
        # several tract GEOIDs are duplicated in the selection. For the sake of clarity, these duplicates
        # are removed from the final vector of GEOIDs.
        tr_ccd_geoid_2012 <- 
                read_csv(
                        root_file('1-data/3-external/manual/seattle-ccd/ACS_12_5YR_B01001/ACS_12_5YR_B01001_with_ann.csv'), 
                        col_types = cols(Id2 = col_character()), 
                        skip = 1) %>% 
                mutate(NEW_GEOID1 = str_sub(Id2,1,5),
                       NEW_GEOID2 = str_sub(Id2,16,21),
                       GEOID = paste0(NEW_GEOID1,NEW_GEOID2),
                       UNIQUE = !duplicated(GEOID)) %>%
                filter(UNIQUE) %>% 
                extract2('GEOID')
        
        
        # All 2015 KC tracts with Seattle CCD subdivision column
        
        tigris::tracts(state = '53',county = '033', year = 2015) %>%
                st_transform(crs_proj@projargs) %>% 
                mutate(SEACCD_LGL = ifelse(GEOID %in% tr_ccd_geoid_2012,TRUE,FALSE)) %>% 
                write_rds(root_file('1-data/4-interim/tr-kc-noclip-2015-sf.rds'))
              
}
# pre-2010 tract boundaries
if(!file.exists(root_file('1-data/4-interim/tr-kc-noclip-2009-sf.rds'))){
        
        # Seattle CCD tracts 
        # Note: because this selection includes all tracts "within or partially-within" the Seattle CC,
        # several tract GEOIDs are duplicated in the selection. For the sake of clarity, these duplicates
        # are removed from the final vector of GEOIDs.
        tr_ccd_geoid_2009 <- 
                read_csv(
                        root_file('1-data/3-external/manual/seattle-ccd/ACS_09_5YR_B01001/ACS_09_5YR_B01001_with_ann.csv'), 
                        col_types = cols(GEO.id2 = col_character())) %>% 
                mutate(NEW_GEOID1 = str_sub(GEO.id2,1,5),
                       NEW_GEOID2 = str_sub(GEO.id2,16,21),
                       GEOID = paste0(NEW_GEOID1,NEW_GEOID2),
                       UNIQUE = !duplicated(GEOID)) %>%
                filter(UNIQUE) %>% 
                extract2('GEOID')
        
        
        # All 2015 KC tracts with Seattle CCD subdivision column
        
        my_dl_zip <- function(url,dir_filepath){
                temp <- tempfile()
                downloader::download(url, dest = temp, mode='wb')
                unzip(temp, exdir = dir_filepath)
                
        }
        
        # my_dl_zip('ftp://ftp.census.gov/geo/tiger/TIGER2009/53_WASHINGTON/53033_King_County/tl_2009_53033_tract00.zip',root_file('1-data/3-external/manual/kc-tr/'))
        # If the download script (above) doesn't work, open this url (https://www.census.gov/cgi-bin/geo/shapefiles2009/county-files?county=53033)
        # and download the 'Census Tract (Census 2000)' file 
        
        readOGR(dsn = root_file('./1-data/3-external/manual/kc-tr/tl_2009_53033_tract00/'),
                layer = 'tl_2009_53033_tract00',
                verbose = FALSE,
                stringsAsFactors = FALSE) %>% 
                st_as_sf() %>% 
                st_transform(crs_proj@projargs) %>% 
                st_cast('MULTIPOLYGON') %>%  
                mutate(SEACCD_LGL = ifelse(CTIDFP00 %in% tr_ccd_geoid_2009,TRUE,FALSE)) %>% 
                write_rds(root_file('1-data/4-interim/tr-kc-noclip-2009-sf.rds'))
                
        
        # Note: the `tigris` package is returning an error for attempts to
        # download tract data before 2011
        # tigris::tracts(state = '53',county = '033', year = 2009) %>%
        #         spTransform(CRSobj = crs_proj) %>%
        #         st_as_sf() %>%
        #         st_cast('MULTIPOLYGON') %>%
        #         mutate(SEACCD_LGL = ifelse(GEOID %in% tr_ccd_geoid_2012,TRUE,FALSE)) %>%
        #         write_rds(root_file('1-data/4-interim/tr-kc-wtr-2009-sf.rds'))
        
}
tr_kc_noclip_2015_sf <- read_rds(root_file('1-data/4-interim/tr-kc-noclip-2015-sf.rds'))
tr_kc_noclip_2009_sf <- read_rds(root_file('1-data/4-interim/tr-kc-noclip-2009-sf.rds'))
show_tr_ccd_noclip_2009_sf <- function(){
        
        blue_orange <- c(blue,orange) %>% unlist
        
        pal <- colorFactor(blue_orange,levels = c(TRUE,FALSE), ordered = TRUE)
        
        myLfltGrey() %>% 
                myLfltOpts() %>% 
                addPolygons(data = as(tr_kc_noclip_2009_sf,"Spatial"),
                            weight = .5,
                            color = ~ pal(SEACCD_LGL),
                            opacity = 1,
                            fillColor = ~ pal(SEACCD_LGL),
                            fillOpacity = .5) %>% 
                addLegend(position = 'bottomright',colors = blue_orange,labels = c('Seattle CCD','Other Tracts'),title = 'pre-2010') %>% 
                miscgis::styleWidget(style = "float:left;margin:1px")
}
show_tr_ccd_noclip_2015_sf <- function(){
        
        blue_orange <- c(blue,orange) %>% unlist
        
        pal <- colorFactor(blue_orange,levels = c(TRUE,FALSE), ordered = TRUE)
        
        myLfltGrey() %>% 
                myLfltOpts() %>% 
                addPolygons(data = as(tr_kc_noclip_2015_sf,"Spatial"),
                            weight = .5,
                            color = ~ pal(SEACCD_LGL),
                            opacity = 1,
                            fillColor = ~ pal(SEACCD_LGL),
                            fillOpacity = .5) %>% 
                addLegend(position = 'bottomright',colors = blue_orange,labels = c('Seattle CCD','Other Tracts'),title = '2010') %>% 
                miscgis::styleWidget(style = "float:none;margin:1px")
}
show_tr_ccd_noclip_2009_sf()

show_tr_ccd_noclip_2015_sf()

King County Waterbodies

These are useful for “clipping” census geographies whose boundaries extend into waterbodies.

if(!file.exists(root_file('1-data/4-interim/wtr-sf.rds'))){
        fp_wtr <- root_file('1-data/3-external/NHDMajor.gdb')
# check if the file already exists, if not then download it
if(!file.exists(fp_wtr)){
        
        url <- "ftp://www.ecy.wa.gov/gis_a/inlandWaters/NHD/NHDmajor.gdb.zip" # save the URL for the waterbodies data
        
        temp <- tempfile() # create a temporary file to hold the compressed download
        
        download(url, dest = temp, mode="wb") # download the file
        
        unzip (temp, exdir = root_file('1-data/3-external/')) # extract the ESRI geodatabase file to a project folder
}
wtr_sf <-
        suppressWarnings(readOGR(dsn = fp_wtr,      # create a waterbodies shape
                layer = "NHD_MajorWaterbodies",verbose = FALSE,pointDropZ = TRUE)) %>%
        gBuffer(byid=TRUE, width=0) %>% # clean up self-intersecting polygons
        spTransform(CRSobj = crs_proj) %>%   # transform the projection to match the project projection
        st_as_sf() %>% 
        st_cast('MULTIPOLYGON') 
wtr_kc_sf <- 
        wtr_sf %>% 
        st_intersects(x = kc_noclip_sf,y = .) %>% 
        unlist(use.names = F) %>% 
        wtr_sf[.,]
# All King County waterbodies
wtr_kc_sf %>% write_rds(root_file('1-data/4-interim/wtr-kc-sf.rds'))
# All waterbodies near Seattle CCD (the Puget Sound area)
wtr_kc_sf %>% 
        st_intersects(x = sea_ccd_noclip_sf,y = .) %>% 
        unlist(use.names = F) %>% 
        wtr_kc_sf[.,] %>% 
        write_rds(root_file('1-data/4-interim/wtr-puget-sf.rds'))
}
although coordinates are longitude/latitude, it is assumed that they are planar
although coordinates are longitude/latitude, it is assumed that they are planar
wtr_kc_sf <- read_rds(root_file('1-data/4-interim/wtr-kc-sf.rds'))
wtr_puget_sf <- read_rds(root_file('1-data/4-interim/wtr-puget-sf.rds'))
show_wtr_kc <- function(){
        myLfltGrey(data = as(wtr_kc_sf,'Spatial')) %>% 
                myLfltOpts() %>% 
                addPolygons(color = blue, opacity = 1, 
                            weight = .5, fillColor = blue,fillOpacity = .5)        
}
show_wtr_kc()

Census Geometries Without (Western) Waterbodies

The same four types of cenus geometries shown above (King County, Seattle CCD, City of Seattle, and all King county tracts) with the major waterbodies removed.

# Clip King County
if(!file.exists(root_file('1-data/4-interim/kc-sf.rds'))){
        kc_noclip_sf %>% 
                mutate(geometry = st_difference(geometry, st_union(wtr_kc_sf))) %>% 
                write_rds(root_file('1-data/4-interim/kc-sf.rds'))
}
# Clip Seattle CCD
if(!file.exists(root_file('1-data/4-interim/seattle-ccd-sf.rds'))){
        sea_ccd_noclip_sf %>% 
                mutate(geometry = st_difference(geometry, st_union(wtr_kc_sf))) %>% 
                st_cast('MULTIPOLYGON') %>% 
                write_rds(root_file('1-data/4-interim/seattle-ccd-sf.rds'))
}
# Clip Seattle
if(!file.exists(root_file('1-data/4-interim/seattle-sf.rds'))){
        sea_noclip_sf %>% 
                mutate(geometry = st_difference(geometry, st_union(wtr_kc_sf))) %>% 
                st_cast('MULTIPOLYGON') %>% 
                write_rds(root_file('1-data/4-interim/seattle-sf.rds'))
}
# Clip King County tracts (2015)
if(!file.exists(root_file('1-data/4-interim/tr-kc-2015-sf.rds'))){
        tr_kc_noclip_2015_sf %>% 
                filter(TRACTCE %!in% '990100') %>% # remove the Puget Sound tract
                mutate(geometry = st_difference(geometry, st_union(wtr_kc_sf))) %>% 
                st_cast('MULTIPOLYGON') %>% 
                write_rds(root_file('1-data/4-interim/tr-kc-2015-sf.rds'))
}
# Clip King County tracts (2009)
if(!file.exists(root_file('1-data/4-interim/tr-kc-2009-sf.rds'))){
        tr_kc_noclip_2009_sf %>% 
                filter(TRACTCE00 %!in% '990100') %>% # remove the Puget Sound tract
                mutate(geometry = st_difference(geometry, st_union(wtr_kc_sf))) %>% 
                st_cast('MULTIPOLYGON') %>% 
                write_rds(root_file('1-data/4-interim/tr-kc-2009-sf.rds'))
}
kc_sf <- read_rds(root_file('1-data/4-interim/kc-sf.rds'))
sea_ccd_sf <- read_rds(root_file('1-data/4-interim/seattle-ccd-sf.rds'))
sea_sf <- read_rds(root_file('1-data/4-interim/seattle-sf.rds'))
show_kc_sf <- function(){
        myLfltGrey(data = as(kc_sf,'Spatial')) %>% 
                myLfltOpts() %>% 
                addPolygons(color = red,opacity = 1,fillColor = red,fillOpacity = .5)
}
show_sea_ccd_sf <- function(){
        myLfltGrey(data = as(sea_ccd_sf,'Spatial')) %>% 
                myLfltOpts() %>% 
                addPolygons(color = blue,opacity = 1,fillColor = blue,fillOpacity = .5)
}
show_sea_sf <- function(){
        myLfltGrey(data = as(sea_sf,'Spatial')) %>% 
                myLfltOpts() %>% 
                addPolygons(color = green,opacity = 1,fillColor = green,fillOpacity = .5)
}
show_kc_sf()

show_sea_ccd_sf()

show_sea_sf()
tr_kc_2015_sf <- read_rds(root_file('1-data/4-interim/tr-kc-2015-sf.rds'))
tr_kc_2009_sf <- read_rds(root_file('1-data/4-interim/tr-kc-2009-sf.rds'))
show_tr_kc_2009_sf <- function(){
        
        blue_orange <- c(blue,orange) %>% unlist
        
        pal <- colorFactor(blue_orange,levels = c(TRUE,FALSE), ordered = TRUE)
        
        myLfltGrey() %>% 
                myLfltOpts() %>% 
                addPolygons(data = as(tr_kc_2009_sf,"Spatial"),
                            weight = .5,
                            color = ~ pal(SEACCD_LGL),
                            opacity = 1,
                            fillColor = ~ pal(SEACCD_LGL),
                            fillOpacity = .5) %>% 
                addLegend(position = 'bottomright',colors = blue_orange,labels = c('Seattle CCD','Other Tracts'),title = 'pre-2010') %>% 
                miscgis::styleWidget(style = "float:left;margin:1px")
}
show_tr_kc_2015_sf <- function(){
        
        blue_orange <- c(blue,orange) %>% unlist
        
        pal <- colorFactor(blue_orange,levels = c(TRUE,FALSE), ordered = TRUE)
        
        myLfltGrey() %>% 
                myLfltOpts() %>% 
                addPolygons(data = as(tr_kc_2015_sf,"Spatial"),
                            weight = .5,
                            color = ~ pal(SEACCD_LGL),
                            opacity = 1,
                            fillColor = ~ pal(SEACCD_LGL),
                            fillOpacity = .5) %>% 
                addLegend(position = 'bottomright',colors = blue_orange,labels = c('Seattle CCD','Other Tracts'),title = '2010') %>% 
                miscgis::styleWidget(style = "float:none;margin:1px")
}
show_tr_kc_2009_sf()

show_tr_kc_2015_sf()

Mixed Census Geometries Simple Feature Object

Add a brief explanation of the sf package

if(!file.exists(root_file('./1-data/4-interim/coo-acs-2015-geoms-sf.rds'))){
        list(
                kc_sf %>% 
                        select(geometry) %>% mutate(NAME = 'KC', NAME_FULL = 'King County, Washington',GEOID6 = NA_character_, SEACCD_LGL = NA),
                sea_ccd_sf %>% 
                        select(geometry) %>% mutate(NAME = 'SEACCD', NAME_FULL = 'Seattle CCD, King County, Washington', GEOID6 = NA_character_, SEACCD_LGL = NA),
                tr_kc_2015_sf %>% 
                        select(NAME,NAME_FULL = NAMELSAD,GEOID6 = GEOID,SEACCD_LGL,geometry) %>% mutate(NAME_FULL = paste0(NAME_FULL,', King County, Washington'),GEOID6 = str_sub(GEOID6,6,11))
        ) %>% 
                reduce(rbind.sf) %>%
                write_rds(root_file('./1-data/4-interim/coo-acs-2015-geoms-sf.rds'))
        
}
if(!file.exists(root_file('./1-data/4-interim/coo-acs-2009-geoms-sf.rds'))){
        list(
                kc_sf %>% 
                        select(geometry) %>% mutate(NAME = 'KC', NAME_FULL = 'King County, Washington',GEOID6 = NA_character_, SEACCD_LGL = NA),
                sea_ccd_sf %>% 
                        select(geometry) %>% mutate(NAME = 'SEACCD', NAME_FULL = 'Seattle CCD, King County, Washington', GEOID6 = NA_character_, SEACCD_LGL = NA),
                tr_kc_2009_sf %>% 
                        select(NAME = NAME00, NAME_FULL = NAMELSAD00,GEOID6 = TRACTCE00,SEACCD_LGL,geometry) %>% mutate(NAME_FULL = paste0(NAME_FULL,', King County, Washington'))
        ) %>% 
                reduce(rbind.sf) %>% 
                write_rds(root_file('./1-data/4-interim/coo-acs-2009-geoms-sf.rds'))
        
}
coo_geoms_2015_sf <- read_rds(root_file('./1-data/4-interim/coo-acs-2015-geoms-sf.rds'))
coo_geoms_2009_sf <- read_rds(root_file('./1-data/4-interim/coo-acs-2009-geoms-sf.rds'))
print(coo_geoms_2015_sf,n =10)
Simple feature collection with 399 features and 4 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -122.5279 ymin: 47.08446 xmax: -121.0657 ymax: 47.78033
epsg (SRID):    NA
proj4string:    NA
First 10 features:
     NAME                                    NAME_FULL GEOID6 SEACCD_LGL                       geometry
1      KC                      King County, Washington   <NA>         NA MULTIPOLYGON(((-122.3943185...
2  SEACCD         Seattle CCD, King County, Washington   <NA>         NA MULTIPOLYGON(((-122.3943185...
3     215    Census Tract 215, King County, Washington 021500       TRUE MULTIPOLYGON(((-122.290323 ...
4  327.04 Census Tract 327.04, King County, Washington 032704      FALSE MULTIPOLYGON(((-121.812202 ...
5     262    Census Tract 262, King County, Washington 026200       TRUE MULTIPOLYGON(((-122.271681 ...
6  327.03 Census Tract 327.03, King County, Washington 032703      FALSE MULTIPOLYGON(((-121.859302 ...
7  323.19 Census Tract 323.19, King County, Washington 032319      FALSE MULTIPOLYGON(((-122.168492 ...
8  323.13 Census Tract 323.13, King County, Washington 032313      FALSE MULTIPOLYGON(((-122.127179 ...
9  316.03 Census Tract 316.03, King County, Washington 031603      FALSE MULTIPOLYGON(((-122.054622 ...
10    297    Census Tract 297, King County, Washington 029700       TRUE MULTIPOLYGON(((-122.256235 ...
LS0tDQpkZl9wcmludDogdGliYmxlDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogIHBkZl9kb2N1bWVudDoNCiAgICBrZWVwX3RleDogeWVzDQphbHdheXNfYWxsb3dfaHRtbDogeWVzDQotLS0NCg0KYGBge3IgbWlzYy1zZXR1cCwgZWNobyA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsY29tbWVudD1GQUxTRX0NCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KG9wZXJhdG9yLnRvb2xzKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkocnByb2pyb290KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJnZGFsKQ0KbGlicmFyeShzcCkNCmxpYnJhcnkocmdlb3MpDQpsaWJyYXJ5KG1pc2NnaXMpDQpsaWJyYXJ5KHRpZ3JpcykNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoZ2d0aGVtZXMpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGRvd25sb2FkZXIpDQpsaWJyYXJ5KG1pc2NnaXMpDQpsaWJyYXJ5KHNmKQ0Kcm9vdCA8LSBycHJvanJvb3Q6OmlzX3JzdHVkaW9fcHJvamVjdA0Kcm9vdF9maWxlIDwtIHJvb3QkbWFrZV9maXhfZmlsZSgpDQpvcHRpb25zKHRpZ3Jpc19jbGFzcyA9ICJzZiIpDQpgYGANCg0KYGBge3IgbWlzYy1jb2xvcnN9DQpncmVlbiA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbWyJncmVlbiJdXQ0KYmx1ZSA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbWyJibHVlIl1dDQpvcmFuZ2UgPC0gbWlzY2dpczo6bWlzY2dpc19wYWxzJHRhYmxlYXVfY2F0W1sib3JhbmdlIl1dDQpyZWQgPC0gbWlzY2dpczo6bWlzY2dpc19wYWxzJHRhYmxlYXVfY2F0W1sicmVkIl1dDQp0ZWFsIDwtIG1pc2NnaXM6Om1pc2NnaXNfcGFscyR0YWJsZWF1X2NhdFtbInRlYWwiXV0NCnBhbF9yZ2JfNCA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbYygicmVkIiwiZ29sZCIsImdyZWVuIiwiYmx1ZSIpXSAlPiUgdW5saXN0ICU+JSBwYWxldHRlKCkNCnBhbF9yZ2JfNCA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbYygicmVkIiwiZ29sZCIsImdyZWVuIiwiYmx1ZSIpXSAlPiUgdW5saXN0ICU+JSBwYWxldHRlKCkNCnBhbF9yZ2JfNiA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbYygicmVkIiwiZ29sZCIsImdyZWVuIiwiYmx1ZSIsIm9yYW5nZSIsInB1cnBsZSIpXSAlPiUgdW5saXN0ICU+JSBwYWxldHRlKCkNCnBhbF9yZ2JfNiA8LSBtaXNjZ2lzOjptaXNjZ2lzX3BhbHMkdGFibGVhdV9jYXRbYygicmVkIiwiZ29sZCIsImdyZWVuIiwiYmx1ZSIsIm9yYW5nZSIsInB1cnBsZSIpXSAlPiUgdW5saXN0ICU+JSBwYWxldHRlKCkNCmBgYA0KDQpCZWxvdyBpcyBhIGNvbGxlY3Rpb24gb2Ygc3BhdGlhbCBkYXRhc2V0cyB1c2VkIGluIHRoaXMgcHJvamVjdC4NCg0KIyMjIEtpbmcgQ291bnR5IEJvdW5kYXJ5DQpgYGB7ciBtaXNjLWtjLCBmaWcuY2FwPSJLaW5nIENvdW50eVwncyBnZW9ncmFwaGljIGJvdW5kYXJ5In0NCg0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2tjLW5vY2xpcC1zZi5yZHMnKSkpew0KICAgICAgICB0aWdyaXM6OmNvdW50aWVzKHN0YXRlID0gIjUzIikgJT4lIA0KICAgICAgICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnNfcHJvakBwcm9qYXJncykgJT4lIA0KICAgICAgICAgICAgICAgIGZpbHRlcihOQU1FICVpbiUgJ0tpbmcnKSAlPiUgDQogICAgICAgICAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2tjLW5vY2xpcC1zZi5yZHMnKSkNCn0NCg0Ka2Nfbm9jbGlwX3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2tjLW5vY2xpcC1zZi5yZHMnKSkNCg0KbXlMZmx0R3JleShkYXRhID0gYXMoa2Nfbm9jbGlwX3NmLCdTcGF0aWFsJykpICU+JSANCiAgICAgICAgbXlMZmx0T3B0cygpICU+JSANCiAgICAgICAgYWRkUG9seWdvbnMoY29sb3IgPSByZWQsb3BhY2l0eSA9IDEsZmlsbENvbG9yID0gcmVkLGZpbGxPcGFjaXR5ID0gLjUpDQpgYGANCg0KDQojIyMgS2luZyBDb3VudHkgU3ViZGl2aXNpb24gQm91bmRhcnkgey19DQoNCmBgYHtyIG1pc2Mtc2VhLWNjZCwgZmlnLmNhcD0iU2VhdHRsZSBTdWJkaXZpc2lvbiBvZiBLaW5nIENvdW50eVwncyBnZW9ncmFwaGljIGJvdW5kYXJ5In0NCg0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLWNjZC1ub2NsaXAtc2YucmRzJykpKXsNCiAgICAgICAgdGlncmlzOjpjb3VudHlfc3ViZGl2aXNpb25zKHN0YXRlID0gIjUzIixjb3VudHkgPSAiMDMzIikgJT4lIA0KICAgICAgICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnNfcHJvakBwcm9qYXJncykgJT4lIA0KICAgICAgICAgICAgICAgIGZpbHRlcihOQU1FICVpbiUgIlNlYXR0bGUiKSAlPiUgDQogICAgICAgICAgICAgICAgbXV0YXRlKE5BTUUgPSAnU2VhdHRsZSBDQ0QnKSAlPiUgDQogICAgICAgICAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLWNjZC1ub2NsaXAtc2YucmRzJykpDQp9DQoNCnNlYV9jY2Rfbm9jbGlwX3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLWNjZC1ub2NsaXAtc2YucmRzJykpDQoNCm15TGZsdEdyZXkoZGF0YSA9IGFzKHNlYV9jY2Rfbm9jbGlwX3NmLCdTcGF0aWFsJykpICU+JSANCiAgICAgICAgbXlMZmx0T3B0cygpICU+JSANCiAgICAgICAgYWRkUG9seWdvbnMoY29sb3IgPSBibHVlLG9wYWNpdHkgPSAxLGZpbGxDb2xvciA9IGJsdWUsZmlsbE9wYWNpdHkgPSAuNSkNCg0KYGBgDQoNCg0KIyMjIFNlYXR0bGUgQm91bmRhcnkgey19DQoNCmBgYHtyIG1pc2Mtc2VhLWJvdW5kLCBmaWcuY2FwPSJTZWF0dGxlXCdzIGdlb2dyYXBoaWMgYm91bmRhcnkifQ0KDQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3NlYXR0bGUtbm9jbGlwLXNmLnJkcycpKSl7DQogICAgICAgIHRpZ3Jpczo6cGxhY2VzKHN0YXRlID0gNTMpICU+JQ0KICAgICAgICAgICAgICAgIHRpZ3Jpczo6ZmlsdGVyX3BsYWNlKHBsYWNlID0gIlNlYXR0bGUiKSAlPiUNCiAgICAgICAgICAgICAgICBzdF90cmFuc2Zvcm0oY3JzX3Byb2pAcHJvamFyZ3MpICU+JSANCiAgICAgICAgICAgICAgICB3cml0ZV9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3NlYXR0bGUtbm9jbGlwLXNmLnJkcycpKQ0KICAgICAgICANCn0NCg0Kc2VhX25vY2xpcF9zZiA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vc2VhdHRsZS1ub2NsaXAtc2YucmRzJykpDQoNCm15TGZsdEdyZXkoZGF0YSA9IGFzKHNlYV9ub2NsaXBfc2YsJ1NwYXRpYWwnKSkgJT4lIA0KICAgICAgICBteUxmbHRPcHRzKCkgJT4lIA0KICAgICAgICBhZGRQb2x5Z29ucyhjb2xvciA9IGdyZWVuLG9wYWNpdHkgPSAxLGZpbGxDb2xvciA9IGdyZWVuLGZpbGxPcGFjaXR5ID0gLjUpDQoNCmBgYA0KDQoNCiMjIyBUcmFjdHMgaW4gS2luZyBDb3VudHkgey19DQpBbHRob3VnaCB0aGlzIGFzc2Vzc21lbnQgaXMgcHJpbWFyaWx5IGZvY3VzZWQgb24gdGhyZWUgY29tbXVuaXRpZXMgd2l0aGluIHRoZSBTZWF0dGxlIENDRCBzdWJkaXZpc2lvbiBvZiBLaW5nIENvdW50eSwgb25lIG9mIHRoZSBpbmRpY2F0b3JzIChob3VzaW5nIG1hcmtldCBjb25kaXRpb25zKSB1c2VzIG5laWdoYm9yaW5nIHRyYWN0cyB0byBkZXRlcm1pbmUgZGlzcGxhY2VtZW50IHJpc2suIFNvbWUgb2YgdGhlIG5laWdoYm9yaW5nIHRyYWN0cyBhcmUgcGFydCBvZiBvdGhlciBjb3VudHkgc3ViZGl2aXNpb24sIGJ1dCByYXRoZXIgdGhhbiB0YXJnZXRpbmcganVzdCB0aG9zZSBzcGVjaWZpYyB0cmFjdHMsIHRoaXMgbWV0aG9kIGNvbGxlY3RzIGRhdGEgZm9yIGFsbCBLaW5nIENvdW50eSB0cmFjdHMgYW5kIHRoZW4gcnVucyB0aGUgYW5hbHlzaXMgb24gdGhlIGFwcHJvcHJpYXRlIHN1YnNldHMuDQoNCkluIHRoZSBhYnNlbmNlIG9mIGEgc3RyYWlnaHQtZm9yd2FyZCBtZXRob2QgZm9yIGlkZW50aWZ5aW5nIGFsbCB0aGUgY2Vuc3VzIHRyYWN0cyBpbiB0aGUgU2VhdHRsZSBDQ0Qgc3ViZGl2aXNpb24gb2YgS2luZyBDb3VudHksIGl0IGlzIHBvc3NpYmxlIHRvIGV4dHJhY3QgdGhpcyBpbmZvcm1hdGlvbiBmcm9tIFtBbWVyaWNhbiBGYWN0ZmluZGVyXShodHRwczovL2ZhY3RmaW5kZXIuY2Vuc3VzLmdvdi9mYWNlcy9uYXYvanNmL3BhZ2VzL2luZGV4LnhodG1sKS4gVGhpcyBbdHV0b3JpYWxdKGh0dHBzOi8vYXNrLmNlbnN1cy5nb3YvcHJ3ZWIvUFJTZXJ2bGV0Q3VzdG9tP3B5QWN0aXZpdHk9cHlNb2JpbGVTbmFwU3RhcnQmQWN0aW9uPXNob3dIYXJuZXNzJlB1cnBvc2U9S01IZWxwU2l0ZVBvcnRhbCZjbGFzc05hbWU9RGF0YS1Qb3J0YWwmUmVhZE9ubHk9dHJ1ZSZwek1vYmlsZUluaXRBY3Rpdml0eT1LTUZldGNoQXJ0aWNsZUV4dGVybmFsJnB6TW9iaWxlSW5pdEFjdGl2aXR5UGFyYW1zPSUyNkFydGljbGVJRCUzREtDUC0zMjU2JnB6TW9iaWxlQ29udGV4dFBhZ2VOYW1lPXB5RGlzcGxheUhhcm5lc3MpIGRlc2NyaWJlcyBob3cgdG8gdXNlIHRoZSBBbWVyaWNhbiBGYWN0ZmluZGVyIGludGVyZmFjZSB0byBleHRyYWN0IGEgbGlzdCBvZiBhbGwgImFsbCB0cmFjdHMgd2l0aGluIChvciBwYXJ0aWFsbHkgd2l0aGluKSBhIGNlbnN1cyBwbGFjZSI7IHN1YnN0aXR1dGluZyAiY291bnR5IHN1YmRpdmlzaW9uIiBmb3IgInBsYWNlIiB3aWxsIHJldHJpZXZlIHRoZSBkZXNpcmVkIHJlc3VsdHMuDQoNClRyYWN0IGJvdW5kYXJpZXMgc29tZXRpbWVzIGNoYW5nZSBvdmVyIHRpbWUsIHBhcnRpY3VsYXJseSBvbiB5ZWFycyB3aGVuIHRoZSBkZWNlbm5pYWwgY2Vuc3VzIGlzIGNvbmR1Y3RlZC4gV2hpbGUgdGhpcyBwcm9qZWN0IHdpbGwgcHJpbWFyaWx5IHVzZSB0aGUgY3VycmVudCBzZXQgb2YgYm91bmRhcmllcywgaXQgaXMgbmVjZXNzYXJ5IHRvIGNvbGxlY3QgdGhlIHRyYWN0IGJvdW5kYXJpZXMgb2YgdGhlIDIwMDAtMjAwOSB0aW1lIHBlcmlvZCBzbyB0aGF0IHRoZXNlIGRhdGFzZXRzIGNhbiBiZSB2aXN1YWxseSByZXByZXNlbnRlZCBpbiBjaG9yb3BsZXRoIGRpYWdyYW1zLg0KDQpgYGB7ciBtaXNjLXRyLWtjLW5vY2xpcCwgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9MiwgZmlnLnNob3c9J2hvbGQnLCBkcGk9MTUwfQ0KIyAyMDE1IHRyYWN0IGJvdW5kYXJpZXMNCmlmKCFmaWxlLmV4aXN0cyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2Mtbm9jbGlwLTIwMTUtc2YucmRzJykpKXsNCiAgICAgICAgDQogICAgICAgICMgU2VhdHRsZSBDQ0QgdHJhY3RzIA0KICAgICAgICAjIE5vdGU6IGJlY2F1c2UgdGhpcyBzZWxlY3Rpb24gaW5jbHVkZXMgYWxsIHRyYWN0cyAid2l0aGluIG9yIHBhcnRpYWxseS13aXRoaW4iIHRoZSBTZWF0dGxlIENDLA0KICAgICAgICAjIHNldmVyYWwgdHJhY3QgR0VPSURzIGFyZSBkdXBsaWNhdGVkIGluIHRoZSBzZWxlY3Rpb24uIEZvciB0aGUgc2FrZSBvZiBjbGFyaXR5LCB0aGVzZSBkdXBsaWNhdGVzDQogICAgICAgICMgYXJlIHJlbW92ZWQgZnJvbSB0aGUgZmluYWwgdmVjdG9yIG9mIEdFT0lEcy4NCiAgICAgICAgdHJfY2NkX2dlb2lkXzIwMTIgPC0gDQogICAgICAgICAgICAgICAgcmVhZF9jc3YoDQogICAgICAgICAgICAgICAgICAgICAgICByb290X2ZpbGUoJzEtZGF0YS8zLWV4dGVybmFsL21hbnVhbC9zZWF0dGxlLWNjZC9BQ1NfMTJfNVlSX0IwMTAwMS9BQ1NfMTJfNVlSX0IwMTAwMV93aXRoX2Fubi5jc3YnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKElkMiA9IGNvbF9jaGFyYWN0ZXIoKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDEpICU+JSANCiAgICAgICAgICAgICAgICBtdXRhdGUoTkVXX0dFT0lEMSA9IHN0cl9zdWIoSWQyLDEsNSksDQogICAgICAgICAgICAgICAgICAgICAgIE5FV19HRU9JRDIgPSBzdHJfc3ViKElkMiwxNiwyMSksDQogICAgICAgICAgICAgICAgICAgICAgIEdFT0lEID0gcGFzdGUwKE5FV19HRU9JRDEsTkVXX0dFT0lEMiksDQogICAgICAgICAgICAgICAgICAgICAgIFVOSVFVRSA9ICFkdXBsaWNhdGVkKEdFT0lEKSkgJT4lDQogICAgICAgICAgICAgICAgZmlsdGVyKFVOSVFVRSkgJT4lIA0KICAgICAgICAgICAgICAgIGV4dHJhY3QyKCdHRU9JRCcpDQogICAgICAgIA0KICAgICAgICANCiAgICAgICAgIyBBbGwgMjAxNSBLQyB0cmFjdHMgd2l0aCBTZWF0dGxlIENDRCBzdWJkaXZpc2lvbiBjb2x1bW4NCiAgICAgICAgDQogICAgICAgIHRpZ3Jpczo6dHJhY3RzKHN0YXRlID0gJzUzJyxjb3VudHkgPSAnMDMzJywgeWVhciA9IDIwMTUpICU+JQ0KICAgICAgICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnNfcHJvakBwcm9qYXJncykgJT4lIA0KICAgICAgICAgICAgICAgIG11dGF0ZShTRUFDQ0RfTEdMID0gaWZlbHNlKEdFT0lEICVpbiUgdHJfY2NkX2dlb2lkXzIwMTIsVFJVRSxGQUxTRSkpICU+JSANCiAgICAgICAgICAgICAgICB3cml0ZV9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3RyLWtjLW5vY2xpcC0yMDE1LXNmLnJkcycpKQ0KICAgICAgICAgICAgICANCn0NCg0KIyBwcmUtMjAxMCB0cmFjdCBib3VuZGFyaWVzDQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3RyLWtjLW5vY2xpcC0yMDA5LXNmLnJkcycpKSl7DQogICAgICAgIA0KICAgICAgICAjIFNlYXR0bGUgQ0NEIHRyYWN0cyANCiAgICAgICAgIyBOb3RlOiBiZWNhdXNlIHRoaXMgc2VsZWN0aW9uIGluY2x1ZGVzIGFsbCB0cmFjdHMgIndpdGhpbiBvciBwYXJ0aWFsbHktd2l0aGluIiB0aGUgU2VhdHRsZSBDQywNCiAgICAgICAgIyBzZXZlcmFsIHRyYWN0IEdFT0lEcyBhcmUgZHVwbGljYXRlZCBpbiB0aGUgc2VsZWN0aW9uLiBGb3IgdGhlIHNha2Ugb2YgY2xhcml0eSwgdGhlc2UgZHVwbGljYXRlcw0KICAgICAgICAjIGFyZSByZW1vdmVkIGZyb20gdGhlIGZpbmFsIHZlY3RvciBvZiBHRU9JRHMuDQogICAgICAgIHRyX2NjZF9nZW9pZF8yMDA5IDwtIA0KICAgICAgICAgICAgICAgIHJlYWRfY3N2KA0KICAgICAgICAgICAgICAgICAgICAgICAgcm9vdF9maWxlKCcxLWRhdGEvMy1leHRlcm5hbC9tYW51YWwvc2VhdHRsZS1jY2QvQUNTXzA5XzVZUl9CMDEwMDEvQUNTXzA5XzVZUl9CMDEwMDFfd2l0aF9hbm4uY3N2JyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhHRU8uaWQyID0gY29sX2NoYXJhY3RlcigpKSkgJT4lIA0KICAgICAgICAgICAgICAgIG11dGF0ZShORVdfR0VPSUQxID0gc3RyX3N1YihHRU8uaWQyLDEsNSksDQogICAgICAgICAgICAgICAgICAgICAgIE5FV19HRU9JRDIgPSBzdHJfc3ViKEdFTy5pZDIsMTYsMjEpLA0KICAgICAgICAgICAgICAgICAgICAgICBHRU9JRCA9IHBhc3RlMChORVdfR0VPSUQxLE5FV19HRU9JRDIpLA0KICAgICAgICAgICAgICAgICAgICAgICBVTklRVUUgPSAhZHVwbGljYXRlZChHRU9JRCkpICU+JQ0KICAgICAgICAgICAgICAgIGZpbHRlcihVTklRVUUpICU+JSANCiAgICAgICAgICAgICAgICBleHRyYWN0MignR0VPSUQnKQ0KICAgICAgICANCiAgICAgICAgDQogICAgICAgICMgQWxsIDIwMTUgS0MgdHJhY3RzIHdpdGggU2VhdHRsZSBDQ0Qgc3ViZGl2aXNpb24gY29sdW1uDQogICAgICAgIA0KICAgICAgICBteV9kbF96aXAgPC0gZnVuY3Rpb24odXJsLGRpcl9maWxlcGF0aCl7DQogICAgICAgICAgICAgICAgdGVtcCA8LSB0ZW1wZmlsZSgpDQogICAgICAgICAgICAgICAgZG93bmxvYWRlcjo6ZG93bmxvYWQodXJsLCBkZXN0ID0gdGVtcCwgbW9kZT0nd2InKQ0KICAgICAgICAgICAgICAgIHVuemlwKHRlbXAsIGV4ZGlyID0gZGlyX2ZpbGVwYXRoKQ0KICAgICAgICAgICAgICAgIA0KICAgICAgICB9DQogICAgICAgIA0KICAgICAgICAjIG15X2RsX3ppcCgnZnRwOi8vZnRwLmNlbnN1cy5nb3YvZ2VvL3RpZ2VyL1RJR0VSMjAwOS81M19XQVNISU5HVE9OLzUzMDMzX0tpbmdfQ291bnR5L3RsXzIwMDlfNTMwMzNfdHJhY3QwMC56aXAnLHJvb3RfZmlsZSgnMS1kYXRhLzMtZXh0ZXJuYWwvbWFudWFsL2tjLXRyLycpKQ0KDQoNCiAgICAgICAgIyBJZiB0aGUgZG93bmxvYWQgc2NyaXB0IChhYm92ZSkgZG9lc24ndCB3b3JrLCBvcGVuIHRoaXMgdXJsIChodHRwczovL3d3dy5jZW5zdXMuZ292L2NnaS1iaW4vZ2VvL3NoYXBlZmlsZXMyMDA5L2NvdW50eS1maWxlcz9jb3VudHk9NTMwMzMpDQogICAgICAgICMgYW5kIGRvd25sb2FkIHRoZSAnQ2Vuc3VzIFRyYWN0IChDZW5zdXMgMjAwMCknIGZpbGUgDQogICAgICAgIA0KICAgICAgICByZWFkT0dSKGRzbiA9IHJvb3RfZmlsZSgnLi8xLWRhdGEvMy1leHRlcm5hbC9tYW51YWwva2MtdHIvdGxfMjAwOV81MzAzM190cmFjdDAwLycpLA0KICAgICAgICAgICAgICAgIGxheWVyID0gJ3RsXzIwMDlfNTMwMzNfdHJhY3QwMCcsDQogICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgJT4lIA0KICAgICAgICAgICAgICAgIHN0X2FzX3NmKCkgJT4lIA0KICAgICAgICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnNfcHJvakBwcm9qYXJncykgJT4lIA0KICAgICAgICAgICAgICAgIHN0X2Nhc3QoJ01VTFRJUE9MWUdPTicpICU+JSAgDQogICAgICAgICAgICAgICAgbXV0YXRlKFNFQUNDRF9MR0wgPSBpZmVsc2UoQ1RJREZQMDAgJWluJSB0cl9jY2RfZ2VvaWRfMjAwOSxUUlVFLEZBTFNFKSkgJT4lIA0KICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2Mtbm9jbGlwLTIwMDktc2YucmRzJykpDQogICAgICAgICAgICAgICAgDQogICAgICAgIA0KICAgICAgICAjIE5vdGU6IHRoZSBgdGlncmlzYCBwYWNrYWdlIGlzIHJldHVybmluZyBhbiBlcnJvciBmb3IgYXR0ZW1wdHMgdG8NCiAgICAgICAgIyBkb3dubG9hZCB0cmFjdCBkYXRhIGJlZm9yZSAyMDExDQogICAgICAgICMgdGlncmlzOjp0cmFjdHMoc3RhdGUgPSAnNTMnLGNvdW50eSA9ICcwMzMnLCB5ZWFyID0gMjAwOSkgJT4lDQogICAgICAgICMgICAgICAgICBzcFRyYW5zZm9ybShDUlNvYmogPSBjcnNfcHJvaikgJT4lDQogICAgICAgICMgICAgICAgICBzdF9hc19zZigpICU+JQ0KICAgICAgICAjICAgICAgICAgc3RfY2FzdCgnTVVMVElQT0xZR09OJykgJT4lDQogICAgICAgICMgICAgICAgICBtdXRhdGUoU0VBQ0NEX0xHTCA9IGlmZWxzZShHRU9JRCAlaW4lIHRyX2NjZF9nZW9pZF8yMDEyLFRSVUUsRkFMU0UpKSAlPiUNCiAgICAgICAgIyAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2Mtd3RyLTIwMDktc2YucmRzJykpDQogICAgICAgIA0KfQ0KDQoNCnRyX2tjX25vY2xpcF8yMDE1X3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS90ci1rYy1ub2NsaXAtMjAxNS1zZi5yZHMnKSkNCg0KdHJfa2Nfbm9jbGlwXzIwMDlfc2YgPC0gcmVhZF9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3RyLWtjLW5vY2xpcC0yMDA5LXNmLnJkcycpKQ0KDQpzaG93X3RyX2NjZF9ub2NsaXBfMjAwOV9zZiA8LSBmdW5jdGlvbigpew0KICAgICAgICANCiAgICAgICAgYmx1ZV9vcmFuZ2UgPC0gYyhibHVlLG9yYW5nZSkgJT4lIHVubGlzdA0KICAgICAgICANCiAgICAgICAgcGFsIDwtIGNvbG9yRmFjdG9yKGJsdWVfb3JhbmdlLGxldmVscyA9IGMoVFJVRSxGQUxTRSksIG9yZGVyZWQgPSBUUlVFKQ0KICAgICAgICANCiAgICAgICAgbXlMZmx0R3JleSgpICU+JSANCiAgICAgICAgICAgICAgICBteUxmbHRPcHRzKCkgJT4lIA0KICAgICAgICAgICAgICAgIGFkZFBvbHlnb25zKGRhdGEgPSBhcyh0cl9rY19ub2NsaXBfMjAwOV9zZiwiU3BhdGlhbCIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodCA9IC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfiBwYWwoU0VBQ0NEX0xHTCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfiBwYWwoU0VBQ0NEX0xHTCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAuNSkgJT4lIA0KICAgICAgICAgICAgICAgIGFkZExlZ2VuZChwb3NpdGlvbiA9ICdib3R0b21yaWdodCcsY29sb3JzID0gYmx1ZV9vcmFuZ2UsbGFiZWxzID0gYygnU2VhdHRsZSBDQ0QnLCdPdGhlciBUcmFjdHMnKSx0aXRsZSA9ICdwcmUtMjAxMCcpICU+JSANCiAgICAgICAgICAgICAgICBtaXNjZ2lzOjpzdHlsZVdpZGdldChzdHlsZSA9ICJmbG9hdDpsZWZ0O21hcmdpbjoxcHgiKQ0KfQ0Kc2hvd190cl9jY2Rfbm9jbGlwXzIwMTVfc2YgPC0gZnVuY3Rpb24oKXsNCiAgICAgICAgDQogICAgICAgIGJsdWVfb3JhbmdlIDwtIGMoYmx1ZSxvcmFuZ2UpICU+JSB1bmxpc3QNCiAgICAgICAgDQogICAgICAgIHBhbCA8LSBjb2xvckZhY3RvcihibHVlX29yYW5nZSxsZXZlbHMgPSBjKFRSVUUsRkFMU0UpLCBvcmRlcmVkID0gVFJVRSkNCiAgICAgICAgDQogICAgICAgIG15TGZsdEdyZXkoKSAlPiUgDQogICAgICAgICAgICAgICAgbXlMZmx0T3B0cygpICU+JSANCiAgICAgICAgICAgICAgICBhZGRQb2x5Z29ucyhkYXRhID0gYXModHJfa2Nfbm9jbGlwXzIwMTVfc2YsIlNwYXRpYWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH4gcGFsKFNFQUNDRF9MR0wpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxDb2xvciA9IH4gcGFsKFNFQUNDRF9MR0wpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gLjUpICU+JSANCiAgICAgICAgICAgICAgICBhZGRMZWdlbmQocG9zaXRpb24gPSAnYm90dG9tcmlnaHQnLGNvbG9ycyA9IGJsdWVfb3JhbmdlLGxhYmVscyA9IGMoJ1NlYXR0bGUgQ0NEJywnT3RoZXIgVHJhY3RzJyksdGl0bGUgPSAnMjAxMCcpICU+JSANCiAgICAgICAgICAgICAgICBtaXNjZ2lzOjpzdHlsZVdpZGdldChzdHlsZSA9ICJmbG9hdDpub25lO21hcmdpbjoxcHgiKQ0KfQ0KDQoNCnNob3dfdHJfY2NkX25vY2xpcF8yMDA5X3NmKCkNCnNob3dfdHJfY2NkX25vY2xpcF8yMDE1X3NmKCkNCg0KDQpgYGANCg0KIyMjIEtpbmcgQ291bnR5IFdhdGVyYm9kaWVzIHstfQ0KDQpUaGVzZSBhcmUgdXNlZnVsIGZvciAiY2xpcHBpbmciIGNlbnN1cyBnZW9ncmFwaGllcyB3aG9zZSBib3VuZGFyaWVzIGV4dGVuZCBpbnRvIHdhdGVyYm9kaWVzLg0KDQpgYGB7ciBtaXNjLXd0ciwgZmlnLmNhcD0iUHVnZXQgU291bmQgd2F0ZXJib2RpZXMifQ0KDQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3d0ci1zZi5yZHMnKSkpew0KICAgICAgICBmcF93dHIgPC0gcm9vdF9maWxlKCcxLWRhdGEvMy1leHRlcm5hbC9OSERNYWpvci5nZGInKQ0KDQojIGNoZWNrIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBpZiBub3QgdGhlbiBkb3dubG9hZCBpdA0KaWYoIWZpbGUuZXhpc3RzKGZwX3d0cikpew0KICAgICAgICANCiAgICAgICAgdXJsIDwtICJmdHA6Ly93d3cuZWN5LndhLmdvdi9naXNfYS9pbmxhbmRXYXRlcnMvTkhEL05IRG1ham9yLmdkYi56aXAiICMgc2F2ZSB0aGUgVVJMIGZvciB0aGUgd2F0ZXJib2RpZXMgZGF0YQ0KICAgICAgICANCiAgICAgICAgdGVtcCA8LSB0ZW1wZmlsZSgpICMgY3JlYXRlIGEgdGVtcG9yYXJ5IGZpbGUgdG8gaG9sZCB0aGUgY29tcHJlc3NlZCBkb3dubG9hZA0KICAgICAgICANCiAgICAgICAgZG93bmxvYWQodXJsLCBkZXN0ID0gdGVtcCwgbW9kZT0id2IiKSAjIGRvd25sb2FkIHRoZSBmaWxlDQogICAgICAgIA0KICAgICAgICB1bnppcCAodGVtcCwgZXhkaXIgPSByb290X2ZpbGUoJzEtZGF0YS8zLWV4dGVybmFsLycpKSAjIGV4dHJhY3QgdGhlIEVTUkkgZ2VvZGF0YWJhc2UgZmlsZSB0byBhIHByb2plY3QgZm9sZGVyDQp9DQoNCnd0cl9zZiA8LQ0KICAgICAgICBzdXBwcmVzc1dhcm5pbmdzKHJlYWRPR1IoZHNuID0gZnBfd3RyLCAgICAgICMgY3JlYXRlIGEgd2F0ZXJib2RpZXMgc2hhcGUNCiAgICAgICAgICAgICAgICBsYXllciA9ICJOSERfTWFqb3JXYXRlcmJvZGllcyIsdmVyYm9zZSA9IEZBTFNFLHBvaW50RHJvcFogPSBUUlVFKSkgJT4lDQogICAgICAgIGdCdWZmZXIoYnlpZD1UUlVFLCB3aWR0aD0wKSAlPiUgIyBjbGVhbiB1cCBzZWxmLWludGVyc2VjdGluZyBwb2x5Z29ucw0KICAgICAgICBzcFRyYW5zZm9ybShDUlNvYmogPSBjcnNfcHJvaikgJT4lICAgIyB0cmFuc2Zvcm0gdGhlIHByb2plY3Rpb24gdG8gbWF0Y2ggdGhlIHByb2plY3QgcHJvamVjdGlvbg0KICAgICAgICBzdF9hc19zZigpICU+JSANCiAgICAgICAgc3RfY2FzdCgnTVVMVElQT0xZR09OJykgDQoNCnd0cl9rY19zZiA8LSANCiAgICAgICAgd3RyX3NmICU+JSANCiAgICAgICAgc3RfaW50ZXJzZWN0cyh4ID0ga2Nfbm9jbGlwX3NmLHkgPSAuKSAlPiUgDQogICAgICAgIHVubGlzdCh1c2UubmFtZXMgPSBGKSAlPiUgDQogICAgICAgIHd0cl9zZlsuLF0NCg0KIyBBbGwgS2luZyBDb3VudHkgd2F0ZXJib2RpZXMNCnd0cl9rY19zZiAlPiUgd3JpdGVfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS93dHIta2Mtc2YucmRzJykpDQoNCiMgQWxsIHdhdGVyYm9kaWVzIG5lYXIgU2VhdHRsZSBDQ0QgKHRoZSBQdWdldCBTb3VuZCBhcmVhKQ0Kd3RyX2tjX3NmICU+JSANCiAgICAgICAgc3RfaW50ZXJzZWN0cyh4ID0gc2VhX2NjZF9ub2NsaXBfc2YseSA9IC4pICU+JSANCiAgICAgICAgdW5saXN0KHVzZS5uYW1lcyA9IEYpICU+JSANCiAgICAgICAgd3RyX2tjX3NmWy4sXSAlPiUgDQogICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vd3RyLXB1Z2V0LXNmLnJkcycpKQ0KfQ0KDQp3dHJfa2Nfc2YgPC0gcmVhZF9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3d0ci1rYy1zZi5yZHMnKSkNCg0Kd3RyX3B1Z2V0X3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS93dHItcHVnZXQtc2YucmRzJykpDQoNCnNob3dfd3RyX2tjIDwtIGZ1bmN0aW9uKCl7DQogICAgICAgIG15TGZsdEdyZXkoZGF0YSA9IGFzKHd0cl9rY19zZiwnU3BhdGlhbCcpKSAlPiUgDQogICAgICAgICAgICAgICAgbXlMZmx0T3B0cygpICU+JSANCiAgICAgICAgICAgICAgICBhZGRQb2x5Z29ucyhjb2xvciA9IGJsdWUsIG9wYWNpdHkgPSAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAuNSwgZmlsbENvbG9yID0gYmx1ZSxmaWxsT3BhY2l0eSA9IC41KSAgICAgICAgDQp9DQoNCnNob3dfd3RyX2tjKCkNCg0KYGBgDQoNCiMjIyBDZW5zdXMgR2VvbWV0cmllcyBXaXRob3V0IChXZXN0ZXJuKSBXYXRlcmJvZGllcyB7LX0NCg0KVGhlIHNhbWUgZm91ciB0eXBlcyBvZiBjZW51cyBnZW9tZXRyaWVzIHNob3duIGFib3ZlIChLaW5nIENvdW50eSwgU2VhdHRsZSBDQ0QsIENpdHkgb2YgU2VhdHRsZSwgYW5kIGFsbCBLaW5nIGNvdW50eSB0cmFjdHMpIHdpdGggdGhlIG1ham9yIHdhdGVyYm9kaWVzIHJlbW92ZWQuDQoNCmBgYHtyIG1pc2MtY2xpcC1nZW9tc30NCg0KIyBDbGlwIEtpbmcgQ291bnR5DQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL2tjLXNmLnJkcycpKSl7DQogICAgICAgIGtjX25vY2xpcF9zZiAlPiUgDQogICAgICAgICAgICAgICAgbXV0YXRlKGdlb21ldHJ5ID0gc3RfZGlmZmVyZW5jZShnZW9tZXRyeSwgc3RfdW5pb24od3RyX2tjX3NmKSkpICU+JSANCiAgICAgICAgICAgICAgICB3cml0ZV9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL2tjLXNmLnJkcycpKQ0KfQ0KDQojIENsaXAgU2VhdHRsZSBDQ0QNCmlmKCFmaWxlLmV4aXN0cyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vc2VhdHRsZS1jY2Qtc2YucmRzJykpKXsNCiAgICAgICAgc2VhX2NjZF9ub2NsaXBfc2YgJT4lIA0KICAgICAgICAgICAgICAgIG11dGF0ZShnZW9tZXRyeSA9IHN0X2RpZmZlcmVuY2UoZ2VvbWV0cnksIHN0X3VuaW9uKHd0cl9rY19zZikpKSAlPiUgDQogICAgICAgICAgICAgICAgc3RfY2FzdCgnTVVMVElQT0xZR09OJykgJT4lIA0KICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vc2VhdHRsZS1jY2Qtc2YucmRzJykpDQp9DQoNCiMgQ2xpcCBTZWF0dGxlDQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL3NlYXR0bGUtc2YucmRzJykpKXsNCiAgICAgICAgc2VhX25vY2xpcF9zZiAlPiUgDQogICAgICAgICAgICAgICAgbXV0YXRlKGdlb21ldHJ5ID0gc3RfZGlmZmVyZW5jZShnZW9tZXRyeSwgc3RfdW5pb24od3RyX2tjX3NmKSkpICU+JSANCiAgICAgICAgICAgICAgICBzdF9jYXN0KCdNVUxUSVBPTFlHT04nKSAlPiUgDQogICAgICAgICAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLXNmLnJkcycpKQ0KfQ0KDQojIENsaXAgS2luZyBDb3VudHkgdHJhY3RzICgyMDE1KQ0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS90ci1rYy0yMDE1LXNmLnJkcycpKSl7DQogICAgICAgIHRyX2tjX25vY2xpcF8yMDE1X3NmICU+JSANCiAgICAgICAgICAgICAgICBmaWx0ZXIoVFJBQ1RDRSAlIWluJSAnOTkwMTAwJykgJT4lICMgcmVtb3ZlIHRoZSBQdWdldCBTb3VuZCB0cmFjdA0KICAgICAgICAgICAgICAgIG11dGF0ZShnZW9tZXRyeSA9IHN0X2RpZmZlcmVuY2UoZ2VvbWV0cnksIHN0X3VuaW9uKHd0cl9rY19zZikpKSAlPiUgDQogICAgICAgICAgICAgICAgc3RfY2FzdCgnTVVMVElQT0xZR09OJykgJT4lIA0KICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2MtMjAxNS1zZi5yZHMnKSkNCn0NCg0KIyBDbGlwIEtpbmcgQ291bnR5IHRyYWN0cyAoMjAwOSkNCmlmKCFmaWxlLmV4aXN0cyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2MtMjAwOS1zZi5yZHMnKSkpew0KICAgICAgICB0cl9rY19ub2NsaXBfMjAwOV9zZiAlPiUgDQogICAgICAgICAgICAgICAgZmlsdGVyKFRSQUNUQ0UwMCAlIWluJSAnOTkwMTAwJykgJT4lICMgcmVtb3ZlIHRoZSBQdWdldCBTb3VuZCB0cmFjdA0KICAgICAgICAgICAgICAgIG11dGF0ZShnZW9tZXRyeSA9IHN0X2RpZmZlcmVuY2UoZ2VvbWV0cnksIHN0X3VuaW9uKHd0cl9rY19zZikpKSAlPiUgDQogICAgICAgICAgICAgICAgc3RfY2FzdCgnTVVMVElQT0xZR09OJykgJT4lIA0KICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2MtMjAwOS1zZi5yZHMnKSkNCn0NCg0KYGBgDQoNCg0KYGBge3IgbWlzYy1zaG93LWNsaXBwZWQtZ2VvbXMtMX0NCg0Ka2Nfc2YgPC0gcmVhZF9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL2tjLXNmLnJkcycpKQ0KDQpzZWFfY2NkX3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLWNjZC1zZi5yZHMnKSkNCg0Kc2VhX3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9zZWF0dGxlLXNmLnJkcycpKQ0KDQpzaG93X2tjX3NmIDwtIGZ1bmN0aW9uKCl7DQogICAgICAgIG15TGZsdEdyZXkoZGF0YSA9IGFzKGtjX3NmLCdTcGF0aWFsJykpICU+JSANCiAgICAgICAgICAgICAgICBteUxmbHRPcHRzKCkgJT4lIA0KICAgICAgICAgICAgICAgIGFkZFBvbHlnb25zKGNvbG9yID0gcmVkLG9wYWNpdHkgPSAxLGZpbGxDb2xvciA9IHJlZCxmaWxsT3BhY2l0eSA9IC41KQ0KfQ0KDQpzaG93X3NlYV9jY2Rfc2YgPC0gZnVuY3Rpb24oKXsNCiAgICAgICAgbXlMZmx0R3JleShkYXRhID0gYXMoc2VhX2NjZF9zZiwnU3BhdGlhbCcpKSAlPiUgDQogICAgICAgICAgICAgICAgbXlMZmx0T3B0cygpICU+JSANCiAgICAgICAgICAgICAgICBhZGRQb2x5Z29ucyhjb2xvciA9IGJsdWUsb3BhY2l0eSA9IDEsZmlsbENvbG9yID0gYmx1ZSxmaWxsT3BhY2l0eSA9IC41KQ0KfQ0KDQpzaG93X3NlYV9zZiA8LSBmdW5jdGlvbigpew0KICAgICAgICBteUxmbHRHcmV5KGRhdGEgPSBhcyhzZWFfc2YsJ1NwYXRpYWwnKSkgJT4lIA0KICAgICAgICAgICAgICAgIG15TGZsdE9wdHMoKSAlPiUgDQogICAgICAgICAgICAgICAgYWRkUG9seWdvbnMoY29sb3IgPSBncmVlbixvcGFjaXR5ID0gMSxmaWxsQ29sb3IgPSBncmVlbixmaWxsT3BhY2l0eSA9IC41KQ0KfQ0Kc2hvd19rY19zZigpDQpzaG93X3NlYV9jY2Rfc2YoKQ0Kc2hvd19zZWFfc2YoKQ0KYGBgDQoNCg0KYGBge3Igc2hvdy1jbGlwcGVkLWdlb21zLTIsIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTIsIGZpZy5zaG93PSdob2xkJywgZHBpPTE1MH0NCg0KdHJfa2NfMjAxNV9zZiA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2MtMjAxNS1zZi5yZHMnKSkNCg0KdHJfa2NfMjAwOV9zZiA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vdHIta2MtMjAwOS1zZi5yZHMnKSkNCg0Kc2hvd190cl9rY18yMDA5X3NmIDwtIGZ1bmN0aW9uKCl7DQogICAgICAgIA0KICAgICAgICBibHVlX29yYW5nZSA8LSBjKGJsdWUsb3JhbmdlKSAlPiUgdW5saXN0DQogICAgICAgIA0KICAgICAgICBwYWwgPC0gY29sb3JGYWN0b3IoYmx1ZV9vcmFuZ2UsbGV2ZWxzID0gYyhUUlVFLEZBTFNFKSwgb3JkZXJlZCA9IFRSVUUpDQogICAgICAgIA0KICAgICAgICBteUxmbHRHcmV5KCkgJT4lIA0KICAgICAgICAgICAgICAgIG15TGZsdE9wdHMoKSAlPiUgDQogICAgICAgICAgICAgICAgYWRkUG9seWdvbnMoZGF0YSA9IGFzKHRyX2tjXzIwMDlfc2YsIlNwYXRpYWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH4gcGFsKFNFQUNDRF9MR0wpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxDb2xvciA9IH4gcGFsKFNFQUNDRF9MR0wpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gLjUpICU+JSANCiAgICAgICAgICAgICAgICBhZGRMZWdlbmQocG9zaXRpb24gPSAnYm90dG9tcmlnaHQnLGNvbG9ycyA9IGJsdWVfb3JhbmdlLGxhYmVscyA9IGMoJ1NlYXR0bGUgQ0NEJywnT3RoZXIgVHJhY3RzJyksdGl0bGUgPSAncHJlLTIwMTAnKSAlPiUgDQogICAgICAgICAgICAgICAgbWlzY2dpczo6c3R5bGVXaWRnZXQoc3R5bGUgPSAiZmxvYXQ6bGVmdDttYXJnaW46MXB4IikNCn0NCg0Kc2hvd190cl9rY18yMDE1X3NmIDwtIGZ1bmN0aW9uKCl7DQogICAgICAgIA0KICAgICAgICBibHVlX29yYW5nZSA8LSBjKGJsdWUsb3JhbmdlKSAlPiUgdW5saXN0DQogICAgICAgIA0KICAgICAgICBwYWwgPC0gY29sb3JGYWN0b3IoYmx1ZV9vcmFuZ2UsbGV2ZWxzID0gYyhUUlVFLEZBTFNFKSwgb3JkZXJlZCA9IFRSVUUpDQogICAgICAgIA0KICAgICAgICBteUxmbHRHcmV5KCkgJT4lIA0KICAgICAgICAgICAgICAgIG15TGZsdE9wdHMoKSAlPiUgDQogICAgICAgICAgICAgICAgYWRkUG9seWdvbnMoZGF0YSA9IGFzKHRyX2tjXzIwMTVfc2YsIlNwYXRpYWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH4gcGFsKFNFQUNDRF9MR0wpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxDb2xvciA9IH4gcGFsKFNFQUNDRF9MR0wpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gLjUpICU+JSANCiAgICAgICAgICAgICAgICBhZGRMZWdlbmQocG9zaXRpb24gPSAnYm90dG9tcmlnaHQnLGNvbG9ycyA9IGJsdWVfb3JhbmdlLGxhYmVscyA9IGMoJ1NlYXR0bGUgQ0NEJywnT3RoZXIgVHJhY3RzJyksdGl0bGUgPSAnMjAxMCcpICU+JSANCiAgICAgICAgICAgICAgICBtaXNjZ2lzOjpzdHlsZVdpZGdldChzdHlsZSA9ICJmbG9hdDpub25lO21hcmdpbjoxcHgiKQ0KfQ0KDQpzaG93X3RyX2tjXzIwMDlfc2YoKQ0KDQpzaG93X3RyX2tjXzIwMTVfc2YoKQ0KDQpgYGANCg0KDQojIyMgTWl4ZWQgQ2Vuc3VzIEdlb21ldHJpZXMgU2ltcGxlIEZlYXR1cmUgT2JqZWN0DQoNCkFkZCBhIGJyaWVmIGV4cGxhbmF0aW9uIG9mIHRoZSBgc2ZgIHBhY2thZ2UNCg0KYGBge3IgbWlzYy1jb21iaW5lZH0NCg0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtMjAxNS1nZW9tcy1zZi5yZHMnKSkpew0KICAgICAgICBsaXN0KA0KICAgICAgICAgICAgICAgIGtjX3NmICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChnZW9tZXRyeSkgJT4lIG11dGF0ZShOQU1FID0gJ0tDJywgTkFNRV9GVUxMID0gJ0tpbmcgQ291bnR5LCBXYXNoaW5ndG9uJyxHRU9JRDYgPSBOQV9jaGFyYWN0ZXJfLCBTRUFDQ0RfTEdMID0gTkEpLA0KICAgICAgICAgICAgICAgIHNlYV9jY2Rfc2YgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGdlb21ldHJ5KSAlPiUgbXV0YXRlKE5BTUUgPSAnU0VBQ0NEJywgTkFNRV9GVUxMID0gJ1NlYXR0bGUgQ0NELCBLaW5nIENvdW50eSwgV2FzaGluZ3RvbicsIEdFT0lENiA9IE5BX2NoYXJhY3Rlcl8sIFNFQUNDRF9MR0wgPSBOQSksDQogICAgICAgICAgICAgICAgdHJfa2NfMjAxNV9zZiAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoTkFNRSxOQU1FX0ZVTEwgPSBOQU1FTFNBRCxHRU9JRDYgPSBHRU9JRCxTRUFDQ0RfTEdMLGdlb21ldHJ5KSAlPiUgbXV0YXRlKE5BTUVfRlVMTCA9IHBhc3RlMChOQU1FX0ZVTEwsJywgS2luZyBDb3VudHksIFdhc2hpbmd0b24nKSxHRU9JRDYgPSBzdHJfc3ViKEdFT0lENiw2LDExKSkNCiAgICAgICAgKSAlPiUgDQogICAgICAgICAgICAgICAgcmVkdWNlKHJiaW5kLnNmKSAlPiUNCiAgICAgICAgICAgICAgICB3cml0ZV9yZHMocm9vdF9maWxlKCcuLzEtZGF0YS80LWludGVyaW0vY29vLWFjcy0yMDE1LWdlb21zLXNmLnJkcycpKQ0KICAgICAgICANCn0NCg0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtMjAwOS1nZW9tcy1zZi5yZHMnKSkpew0KICAgICAgICBsaXN0KA0KICAgICAgICAgICAgICAgIGtjX3NmICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChnZW9tZXRyeSkgJT4lIG11dGF0ZShOQU1FID0gJ0tDJywgTkFNRV9GVUxMID0gJ0tpbmcgQ291bnR5LCBXYXNoaW5ndG9uJyxHRU9JRDYgPSBOQV9jaGFyYWN0ZXJfLCBTRUFDQ0RfTEdMID0gTkEpLA0KICAgICAgICAgICAgICAgIHNlYV9jY2Rfc2YgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGdlb21ldHJ5KSAlPiUgbXV0YXRlKE5BTUUgPSAnU0VBQ0NEJywgTkFNRV9GVUxMID0gJ1NlYXR0bGUgQ0NELCBLaW5nIENvdW50eSwgV2FzaGluZ3RvbicsIEdFT0lENiA9IE5BX2NoYXJhY3Rlcl8sIFNFQUNDRF9MR0wgPSBOQSksDQogICAgICAgICAgICAgICAgdHJfa2NfMjAwOV9zZiAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoTkFNRSA9IE5BTUUwMCwgTkFNRV9GVUxMID0gTkFNRUxTQUQwMCxHRU9JRDYgPSBUUkFDVENFMDAsU0VBQ0NEX0xHTCxnZW9tZXRyeSkgJT4lIG11dGF0ZShOQU1FX0ZVTEwgPSBwYXN0ZTAoTkFNRV9GVUxMLCcsIEtpbmcgQ291bnR5LCBXYXNoaW5ndG9uJykpDQogICAgICAgICkgJT4lIA0KICAgICAgICAgICAgICAgIHJlZHVjZShyYmluZC5zZikgJT4lIA0KICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJy4vMS1kYXRhLzQtaW50ZXJpbS9jb28tYWNzLTIwMDktZ2VvbXMtc2YucmRzJykpDQogICAgICAgIA0KfQ0KDQoNCmNvb19nZW9tc18yMDE1X3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtMjAxNS1nZW9tcy1zZi5yZHMnKSkNCg0KY29vX2dlb21zXzIwMDlfc2YgPC0gcmVhZF9yZHMocm9vdF9maWxlKCcuLzEtZGF0YS80LWludGVyaW0vY29vLWFjcy0yMDA5LWdlb21zLXNmLnJkcycpKQ0KDQpwcmludChjb29fZ2VvbXNfMjAxNV9zZixuID0xMCkNCg0KYGBgDQoNCg==